`timescale 10ns/1ns 

module sdram_controller(

	input		    				    RE                  ,   //使能
	input		    				    WR                  ,		                
	output		                        RD_REQUEST_APPROVED ,   //反馈
	output 		                        WR_REQUEST_APPROVED ,
    
    input		        [24:0]		    ADDR                ,
	input				[15:0]          WR_DATA             ,
    output  	        [15:0]		    RD_DATA             ,
	
	//////////// CLOCK //////////
	input 		          		        MAX10_CLK1_100      ,   //系统时钟
	input 		          		        MAX10_CLK2_100_3ns  , 	//SDRAM时钟
    input 		          		        reset_n             ,
	//////////// SDRAM //////////
	output		        [12:0]		    DRAM_ADDR           ,
	output		        [1:0]		    DRAM_BA             ,
	output		          		        DRAM_CAS_N          ,
	output		          		        DRAM_CKE            ,
	output		          		        DRAM_CLK            ,
	output		          		        DRAM_CS_N           ,
	inout 		        [15:0]		    DRAM_DQ             ,
	output		          		        DRAM_LDQM           ,
	output		          		        DRAM_RAS_N          ,
	output		          		        DRAM_UDQM           ,
	output		          		        DRAM_WE_N

	);
    
//init
wire                            init_end_flag                   ;
wire    [ 2:0]                  init_cmd                        ;
wire    [12:0]                  init_addr                       ;
wire    [ 1:0]                  init_ba                         ;

//refresh
parameter                       REFRESH_64ms_COUNT      	    =	    23'd6400000 ;	//刷新64ms阈值，64ms/10ns
parameter                       REFRESH_CYCLE_PULSE_WIDTH_1     =       23'd6340000 ;	//提前0.1ms宣布刷新，左边界
parameter                       REFRESH_CYCLE_PULSE_WIDTH_2     =       23'd6350000 ;	//提前0.1ms宣布刷新，右边界
reg     [22:0]                  refresh_count_timer             =       23'd0       ;   //计数刷新64ms
reg                             refresh_flag                    =       1'b0        ;
reg                             refresh_flag_ack                =       1'b0        ;
wire    [ 2:0]                  refresh_cmd                     ;
wire                            refresh_end_flag                ;


//read
reg                             read_flag_ack       =       1'b0;
wire                            read_end_flag                   ;
wire    [ 2:0]                  read_cmd                        ;
wire    [12:0]                  read_addr                       ;
wire    [ 1:0]                  read_ba                         ;
wire    [ 1:0]                  read_dqm                        ;

//write
reg                             write_flag_ack      =       1'b0;
wire                            write_end_flag                  ;
wire    [ 2:0]                  write_cmd                       ;
wire    [12:0]                  write_addr                      ;
wire    [ 1:0]                  write_ba                        ;
wire    [ 1:0]                  write_dqm                       ;


/////////////////////命令 ras_n cas_n we_n
parameter               [2:0]           CMD_LOADMODE  		=       3'b000;	
parameter               [2:0]           CMD_AUTO_REFRESH    =       3'b001;
parameter               [2:0]           CMD_PRECHARGE 		=       3'b010;
parameter               [2:0]           CMD_ACTIVE    		=       3'b011;
parameter               [2:0]           CMD_WRITE     		=       3'b100;
parameter               [2:0]           CMD_READ      		=       3'b101;
parameter               [2:0]           CMD_NOP       		=       3'b111;
wire [2:0] CMD;

////////////////////状态
parameter
//初始化
Init_state                                      =       5'b00001,

//空闲
idle_state                                      =       5'b00110,
//激活
activate_state                                  =       5'b00111,
activate_NOP_state                              =       5'b01000,
//读
read_state                                      =       5'b01001,
//写
write_state                                     =       5'b11100,
//预充电
Precharge_state                                 =       5'b01100,
Precharge_NOP_state                             =       5'b01101,
//自动刷新
Auto_Refresh_state                              =       5'b01110;

reg[4:0] current_state ;


///////////////////主程序
always @(posedge MAX10_CLK1_100)//每64ms自动刷新一次标志

		begin
				
					if(refresh_count_timer < REFRESH_64ms_COUNT)
						begin
							refresh_count_timer <=refresh_count_timer+1;
							if( (refresh_count_timer > REFRESH_CYCLE_PULSE_WIDTH_1 && refresh_count_timer < REFRESH_CYCLE_PULSE_WIDTH_2))
								begin
									refresh_flag <=1'b1;//在接近64ms的时候宣布刷新
								end
							else
								refresh_flag<=1'b0;
						end
					else
						begin
							refresh_count_timer <=23'd1;//重新64ms的计数
							refresh_flag<=1'b0;
						end
	
		end

always @(posedge MAX10_CLK1_100)//状态机
		begin
			
			if(!reset_n)	//判断复位信号		
                begin
					current_state=Init_state;
				end
			else
				begin
                    case (current_state)
                        Init_state:	//初始化
								begin
									  			
									if (init_end_flag==1'b1)//初始化结束
										begin
											current_state=idle_state;   //进入空闲状态
										end
									else
										current_state=Init_state;//继续初始化
																  
								end
                        idle_state:
                                if(refresh_flag && !refresh_flag_ack)	//判断刷新
									begin
										refresh_flag_ack<=1'b1;
										current_state=Auto_Refresh_state;			
										
									end
								else if(!RE && read_flag_ack) //判断读
									begin
										read_flag_ack=1'b0;
									end
								else if(RE && !read_flag_ack)
									begin
										read_flag_ack<=1'b1;
										current_state=activate_state;
									end
									
								else if(!WR && write_flag_ack) //判断写
									begin
										write_flag_ack=1'b0;
									end
								else if(WR && !write_flag_ack)
									begin
										write_flag_ack<=1'b1;
										current_state=activate_state;
									end
                        Auto_Refresh_state://刷新
                                if(refresh_end_flag==1'b1)
                                    begin
										refresh_flag_ack<=1'b0;
										current_state=idle_state;
                                    end
                                else
                                    current_state=Auto_Refresh_state;
                        activate_state://激活
                                begin
										current_state=activate_NOP_state;
								end
								activate_NOP_state: 
									begin
										if(read_flag_ack)	
											begin
												current_state=read_state;
											end
										else if(write_flag_ack)
											begin
												current_state=write_state;
											end
										
									end
                         write_state://写
                                begin
                                    if(write_end_flag==1'b1)
                                        begin
                                            write_flag_ack=1'b0;
                                            current_state=idle_state;
                                        end
                                    else
                                        current_state=write_state;
                                end                           
                         read_state://读
                                begin
                                    if(read_end_flag==1'b1)
                                        begin
                                            read_flag_ack=1'b0;
                                            current_state=idle_state;
                                        end
                                    else
                                        current_state=read_state;
                                end
                        default : 
                            current_state<=idle_state;
					endcase
				end	
        end

//CKE，CS
assign      DRAM_CKE=1'b1; 
assign      DRAM_CS_N=1'b0;

//命令
assign      {DRAM_RAS_N, DRAM_CAS_N, DRAM_WE_N} = CMD;
assign CMD =(current_state==Init_state)?init_cmd:
(current_state==activate_state)?CMD_ACTIVE:
(current_state==read_state)?read_cmd:
(current_state==write_state)?write_cmd:
(current_state==Auto_Refresh_state)?refresh_cmd:CMD_NOP;

//SDRAM时钟
assign      DRAM_CLK=MAX10_CLK2_100_3ns;    

//用户反馈
assign      RD_REQUEST_APPROVED = read_flag_ack;    
assign      WR_REQUEST_APPROVED = write_flag_ack;

//数据掩码
assign {DRAM_UDQM,DRAM_LDQM} = (current_state==write_state)?write_dqm:(current_state==read_state)?read_dqm:2'b11;

//地址
assign {DRAM_BA,DRAM_ADDR}=(current_state==activate_state)? ADDR[24:10]:
       (current_state==read_state)? {read_ba,read_addr}:
       (current_state==write_state)?{write_ba,write_addr}:
       (current_state==Init_state)? {init_ba,init_addr}:{15{1'b0}};	



//子模块例化
sdram_init      sdram_init_inst(
        .clk                        (MAX10_CLK1_100         ),              
        .cmd                        (init_cmd               ),
        .init_addr                  (init_addr              ),
        .init_end_flag              (init_end_flag          ),
        .init_ba                    (init_ba                )
);

sdram_refresh   sdram_refresh_inst(
        .clk                        (MAX10_CLK1_100         ),
        .refresh_flag               (refresh_flag           ),         
        .cmd                        (refresh_cmd            ),
        .refresh_end_flag           (refresh_end_flag       )
);

sdram_read      sdram_read_inst(
        .clk                        (MAX10_CLK1_100         ),
        .clk_3ns                    (MAX10_CLK2_100_3ns     ),
        .refresh_flag               (refresh_flag           ),
        .re                         (RE                     ),
        .dq                         (DRAM_DQ                ),
        .dqm                        (read_dqm               ),
        .addr                       (ADDR                   ),
        .read_addr                  (read_addr              ),
        .read_ba                    (read_ba                ),
        .cmd                        (read_cmd               ),
        .data                       (RD_DATA                ),
        .read_end_flag              (read_end_flag          )

);

sdram_write      sdram_write_inst(
        .clk                        (MAX10_CLK1_100         ),
        .refresh_flag               (refresh_flag           ),
        .wr                         (WR                     ),
        .dq                         (DRAM_DQ                ),
        .dqm                        (write_dqm              ),
        .addr                       (ADDR                   ),
        .data                       (WR_DATA                ),
        .write_addr                 (write_addr             ),
        .write_ba                   (write_ba               ),
        .cmd                        (write_cmd              ),
        .write_end_flag             (write_end_flag         )

);

endmodule








